package com.hzjh.base.router.ext

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import com.alibaba.android.arouter.facade.Postcard
import com.alibaba.android.arouter.facade.callback.NavigationCallback
import com.alibaba.android.arouter.launcher.ARouter
import java.io.Serializable

fun <T> lazyOnNone(initializer: () -> T) = lazy(mode = LazyThreadSafetyMode.NONE, initializer)
fun <T> lazyOnSync(initializer: () -> T) =
    lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED, initializer)

/**
 * 路由导航
 */
fun Context.navigation(path: String, bundle: Bundle? = null) {
    navigationTo(path) {
        with(bundle)
    }
}

/**
 * 路由导航
 * [Context]扩展包含函数， 可支持返回Fragment?,Service?,IProvider等ARouter注解的对象
 */
fun Context.navigationTo(
    url: String?,
    requestCode: Int = Int.MIN_VALUE,
    greenChannel: Boolean = false,
    params: (Postcard.() -> Unit)? = null
): Any? {
    url ?: return null
    val postcard = preRouteBuild(url)
    if (greenChannel) {
        postcard.greenChannel()
    }
    params?.let {
        postcard.params()
    }
    return if (this is Activity && requestCode != Int.MIN_VALUE) {
        postcard.navigation(this, requestCode)
        null
    } else {
        postcard.navigation(this)
    }
}

/**
 * 简单路由导航
 */
fun navigation(path: String, bundle: Bundle? = null) {
    navigationTo(path) {
        with(bundle)
    }
}

/**
 * 路由导航多参数，url为Uri推荐使用[navigateUri]
 */
fun navigationTo(
    url: String?,
    greenChannel: Boolean = false,
    onLost: (() -> Unit)? = null,
    params: (Postcard.() -> Unit)? = null
) {
    url ?: return
    val postcard = preRouteBuild(url)
    if (greenChannel) {
        postcard.greenChannel()
    }
    params?.let {
        postcard.params()
    }
    if (onLost != null) {
        postcard.navigation(null, object : NavigationCallback {
            override fun onFound(postcard: Postcard?) {

            }

            override fun onLost(postcard: Postcard?) {
                onLost.invoke()
            }

            override fun onArrival(postcard: Postcard?) {

            }

            override fun onInterrupt(postcard: Postcard?) {

            }

        })
    } else {
        postcard.navigation()
    }
}

/**
 * 路由导航，Uri中有参数ARoute自动转换
 * @param uri 最好带有scheme，否则Uri.parse可能导致内部路由异常
 */
fun navigateUri(
    uri: Uri?,
    onLost: (() -> Unit)? = null,
    params: (Postcard.() -> Unit)? = null,
) {
    val postcard = ARouter.getInstance().build(uri)
    params?.run {
        postcard.params()
    }
    if (onLost != null) {
        postcard.navigation(null, object : NavigationCallback {
            override fun onFound(postcard: Postcard?) {

            }

            override fun onLost(postcard: Postcard?) {
                onLost.invoke()
            }

            override fun onArrival(postcard: Postcard?) {

            }

            override fun onInterrupt(postcard: Postcard?) {

            }

        })
    } else {
        postcard.navigation()
    }
}

/**
 * 预处理
 */
internal fun preRouteBuild(url: String): Postcard {
    val router = ARouter.getInstance()
    return router.build(url)
}


fun Postcard.extraOf(vararg pairs: Pair<String, @JvmSuppressWildcards Any?>) {
    if (!pairs.isNullOrEmpty()) {
        for ((key, value) in pairs) {
            if (value == null) continue
            when (value) {
                is Boolean -> withBoolean(key, value)
                is Byte -> withByte(key, value)
                is Char -> withChar(key, value)
                is Double -> withDouble(key, value)
                is Float -> withFloat(key, value)
                is Int -> withInt(key, value)
                is Long -> withLong(key, value)
                is Short -> withShort(key, value)

                is Bundle -> withBundle(key, value)
                is CharSequence -> withCharSequence(key, value)
                is Parcelable -> withParcelable(key, value)
                is ByteArray -> withByteArray(key, value)
                is CharArray -> withCharArray(key, value)
                is FloatArray -> withFloatArray(key, value)
                is ShortArray -> withShortArray(key, value)

                is Array<*> -> {
                    @Suppress("UNCHECKED_CAST")
                    when {
                        value.isArrayOf<Parcelable>() ->
                            withParcelableArray(key, value as Array<Parcelable>)
                        value.isArrayOf<CharSequence>() ->
                            withCharSequenceArray(key, value as Array<CharSequence?>)
                    }
                }

                is ArrayList<*> -> {
                    val componentType = value::class.java.componentType!!
                    @Suppress("UNCHECKED_CAST")
                    when {
                        Parcelable::class.java.isAssignableFrom(componentType) -> {
                            withParcelableArrayList(key, value as ArrayList<Parcelable>)
                        }
                        String::class.java.isAssignableFrom(componentType) -> {
                            withStringArrayList(key, value as ArrayList<String>)
                        }
                        CharSequence::class.java.isAssignableFrom(componentType) -> {
                            withCharSequenceArrayList(key, value as ArrayList<CharSequence>)
                        }
                    }
                }

                is Serializable -> withSerializable(key, value)
                else -> withObject(key, value)
            }
        }
    }
}

@Suppress("UNCHECKED_CAST")
fun Bundle.extra(vararg pairs: Pair<String, Any>) {
    if (!pairs.isNullOrEmpty()) {
        for ((key, value) in pairs) {
            when (value) {
                is Boolean -> putBoolean(key, value)
                is Byte -> putByte(key, value)
                is Char -> putChar(key, value)
                is Double -> putDouble(key, value)
                is Float -> putFloat(key, value)
                is Int -> putInt(key, value)
                is Long -> putLong(key, value)
                is Short -> putShort(key, value)

                is Bundle -> putBundle(key, value)
                is CharSequence -> putCharSequence(key, value)
                is Parcelable -> putParcelable(key, value)
                is ByteArray -> putByteArray(key, value)
                is CharArray -> putCharArray(key, value)
                is FloatArray -> putFloatArray(key, value)
                is ShortArray -> putShortArray(key, value)

                is Array<*> -> {
                    when {
                        value.isArrayOf<Parcelable>() ->
                            putParcelableArray(key, value as Array<Parcelable>)
                        value.isArrayOf<CharSequence>() ->
                            putCharSequenceArray(key, value as Array<CharSequence?>)
                    }
                }

                is ArrayList<*> -> {
                    val componentType = value::class.java.componentType!!
                    when {
                        Parcelable::class.java.isAssignableFrom(componentType) -> {
                            putParcelableArrayList(key, value as ArrayList<Parcelable>)
                        }
                        String::class.java.isAssignableFrom(componentType) -> {
                            putStringArrayList(key, value as ArrayList<String>)
                        }
                        CharSequence::class.java.isAssignableFrom(componentType) -> {
                            putCharSequenceArrayList(key, value as ArrayList<CharSequence>)
                        }
                    }
                }

                is Serializable -> putSerializable(key, value)
                else -> {
                    // do nothing
                }
            }
        }
    }
}

inline fun <reified T> Context.start(noinline params: (Intent.() -> Unit)? = null) {
    this.startActivity(Intent(this, T::class.java).apply {
        params?.invoke(this)
    })
}